진~~~짜 유용하게 잘 쓰일 것 같은 챕터다.
스크롤을 내리면 비어있던 이미지들이 위치에 맞게 슬라이드 인 되는 기능이다.
🤔 그동안은 클릭이나 키다운에 의한 이벤트 함수를 생성했었는데,
이번 챕터에서는 스크롤한 위치에 따른 기능실행이라는 점이 신선했던 것 같다.
로직
- const
- eventListener + 함수생성
- offset값을 활용한 위치값 불러오기
const!
1
| const slideIn = document.querySelectorAll('.slide-in');
|
이벤트리스너와 함수
1 2 3 4 5
| function slide(e) { console.log(e); }
window.addEventListener('scroll', slide);
|
하지만, 이렇게 둘 경우 너무 자주 함수(slide)가 실행되어 비효율적일 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
function debounce(func, wait = 10, immediate = true) { var timeout; return function () { var context = this, args = arguments; var later = function () { timeout = null; if (!immediate) func.apply(context, args); }; var callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func.apply(context, args); }; }
window.addEventListener('scroll', debounce(slide));
|
offset 값을 활용!
💡 scrollY : 세로로 스크롤이 몇 px만큼 움직였는지 알 수 있음
💡 innerHeight : 현재 뷰포트의 세로값(px)을 알 수 있음
어느 위치를 기준으로 이미지가 슬라이드 인 되어야 할까?
🤔 이미지의 세로 중간 쯤 뷰포트 바텀라인이 도착하면 슬라이드인 되도록 하는 것이 자연스러울 것 같다.
💡 그럼 ! 일단 현재 얼마나 스크롤 됐는지에 대한 값을 불러오는 변수를 설정해주자.
얼마나 스크롤 됐는지?
❗ 뷰포트 바닥을 기준으로 계산을 할 것이다. (상단 기준이면 scrollY만 있어도 됨)
1 2 3
| const slideAt = window.scrollY + window.innerHeight; console.log(slideAt);
|
이미지의 바닥 위치
1 2
| const imageBottom = slideImage.offsetTop + slideImage.height;
|
offsetTop?
💡 부모의 상단 보더로부터 자신의 상단 보더가 떨어진 만큼의 거리!
슬라이드인 조건들
스크롤이 이미지의 절반까지 위치했는가?
1
| const isHalfShown = slideAt > slideImage.offsetTop + slideImage.height / 2;
|
화면에서 이미지가 이미 지나쳐갔는가?
1 2
| const isPassed = window.scrollY < imageBottom;
|
이제 이미지를 위의 두 조건이 아닐 경우에는 이미지가 슬라이드 아웃 되도록 해주면 된다.
최종 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| function debounce(func, wait = 10, immediate = true) { var timeout; return function () { var context = this, args = arguments; var later = function () { timeout = null; if (!immediate) func.apply(context, args); }; var callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func.apply(context, args); }; }
const slideIn = document.querySelectorAll('.slide-in');
function slide(e) { slideIn.forEach((slideImage) => { const slideAt = window.scrollY + window.innerHeight; console.log(slideAt); console.dir(slideImage); const imageBottom = slideImage.offsetTop + slideImage.height; const isHalfShown = slideAt > slideImage.offsetTop + slideImage.height / 2; const isPassed = window.scrollY < imageBottom; if (isHalfShown && isPassed) { slideImage.classList.add('active'); } else { slideImage.classList.remove('active'); } }); }
window.addEventListener('scroll', debounce(slide));
|